package org.hs.phd.common.frameviewer;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;

public class ViewerCanvas extends Component implements MouseListener, MouseMotionListener {

	private static final Dimension DEFAULT_PREFERRED_DIMS = new Dimension(800, 650);

	private static final long serialVersionUID = 1L;

	private final FrameViewer viewer;

	private List<ViewerLayer> layers;
	private BufferedImage image;

	private Dimension preferredDimension;
	private float scale;

	public ViewerCanvas(FrameViewer viewer) {
		this.viewer = viewer;
		this.setScale(1);
		layers = new ArrayList<ViewerLayer>();
		preferredDimension = DEFAULT_PREFERRED_DIMS;
		addMouseListener(this);
		addMouseMotionListener(this);
	}

	public void addLayer(ViewerLayer layer) {
		layers.add(layer);
	}

	public void setImage(BufferedImage image) {
		this.image = image;
		
		updateUI();
	}

	private void updateUI() {
		if(image != null){
			preferredDimension = new Dimension(Math.round(scale*image.getWidth()), Math.round(scale*image.getHeight()));
		}else{
			preferredDimension = DEFAULT_PREFERRED_DIMS;
		}

		invalidate();
		Container parent = getParent();
		if( parent != null ){
			parent.validate();
		}
	}
	
	@Override
	public void paint(Graphics g) {
		
		Graphics2D g2 = (Graphics2D) g;

		if( image != null ){
			g2.drawImage(image, 0, 0, Math.round(image.getWidth()*scale), Math.round(image.getHeight()*scale), null);
		}
		
		for( ViewerLayer layer : layers ){
			if( layer.isEnabled() ){
				layer.paint(g2);
			}
		}
	}
	
	@Override
	public Dimension getPreferredSize() {
		return preferredDimension;
	}

	public float getScale() {
		return scale;
	}

	public final void setScale(float scale) {
		this.scale = scale;
		repaint();
		updateUI();
	}
	
	public Point viewToModel(int x, int y) {
		return new Point(Math.round(x/scale),Math.round(y/scale) );
	}

	public Point modelToView(int x, int y) {
		return new Point(Math.round(x*scale),Math.round(y*scale) );
	}

	@Override
	public void mouseDragged(MouseEvent e) {
		for( ViewerLayer layer : layers ){
			if( layer.isEnabled() ){
				layer.mouseDragged(e);
			}
		}
	}

	@Override
	public void mouseMoved(MouseEvent e) {
		for( ViewerLayer layer : layers ){
			if( layer.isEnabled() ){
				layer.mouseMoved(e);
			}
		}
	}

	@Override
	public void mouseClicked(MouseEvent e) {
		for( ViewerLayer layer : layers ){
			if( layer.isEnabled() ){
				layer.mouseClicked(e);
			}
		}
	}

	@Override
	public void mousePressed(MouseEvent e) {
		for( ViewerLayer layer : layers ){
			if( layer.isEnabled() ){
				layer.mousePressed(e);
			}
		}
	}

	@Override
	public void mouseReleased(MouseEvent e) {
		for( ViewerLayer layer : layers ){
			if( layer.isEnabled() ){
				layer.mouseReleased(e);
			}
		}
	}

	@Override
	public void mouseEntered(MouseEvent e) {
		for( ViewerLayer layer : layers ){
			if( layer.isEnabled() ){
				layer.mouseEntered(e);
			}
		}
	}

	@Override
	public void mouseExited(MouseEvent e) {
		for( ViewerLayer layer : layers ){
			if( layer.isEnabled() ){
				layer.mouseExited(e);
			}
		}
	}

}
